44 数据结构之字典
本章定位(复习与补充训练层):本章对应正课第2章《列表、字典和元组》(章节 2)的字典部分,并与第37章《数据基本结构(元组、列表、字典)》(章节 38)互为补充训练(本章为分项版),用于复习、补缺与额外练习。建议先不看讲解,直接尝试下方平台任务,再对照解析补弱项。本章不属于必修主线。先做本章『动手与思考』第 1 题与平台任务自测,通过即可跳过本章。
44.1 引言字典的键值对与哈希表
字典(Dict)按键存取值:键唯一且必须是不可变类型,平均查找复杂度为O(1),是”股票代码到名称”“日期到行情”这类映射关系的首选结构。本章用一个含四个小任务的平台代码块,检验你对字典创建、查询、修改与增删的复习效果。
44.2 本章学习目标
本章为复习与补充训练,目标是检验你是否能脱离正课独立完成下列任务:
- 能独立完成平台任务一:创建四个汇率信息字典,分别输出
keys()、values()、items() - 能独立完成平台任务二:用键直接查询
dict1["日期"]、dict2["中间价"]、dict4["涨跌幅"] - 能独立完成平台任务三:按键修改已有键值对(
dict2["日期"] = "2024-08-29"等)后输出整个字典 - 能独立完成平台任务四:用
update()批量新增”前一日中间价”“前一日涨跌幅”,并用del dict4["涨跌幅"]删除键 - 能说出
d[key]与d.get(key, default)的区别,并写出基本的字典推导式
若上述任务无法独立完成,请回到正课第2章字典部分补弱,再回到本章练习。
44.3 字典的创建
先概括字典的四大核心特性,创建与操作方式都由此决定:
字典的四大核心特性:
| 特性 | 技术实现 | 时间复杂度 | 金融应用场景 |
|---|---|---|---|
| 键唯一性 | 哈希表约束 | - | 股票代码映射 |
| 快速查找 | 哈希计算 | O(1)平均 | 实时行情查询 |
| 有序性(Python 3.7+) | 维护插入顺序 | O(1) | 时间序列索引 |
| 异构性 | 键值可变类型 | - | 多维度数据 |
平台任务(平台原始代码)
以下代码与教学平台任务要求完全一致:
任务要求(单块含任务一至任务四):给定四个汇率信息字典 dict1~dict4(键均为”汇率变量”“日期”“中间价”“涨跌幅”)。 - 任务一:分别输出 dict1.keys()、dict2.values()、dict3.items(); - 任务二:用键直接查询并输出 dict1["日期"]、dict2["中间价"]、dict4["涨跌幅"]; - 任务三:按键修改 dict2 的日期、中间价、涨跌幅三个键值对后输出整个字典; - 任务四:用 update() 向 dict3 批量新增”前一日中间价”“前一日涨跌幅”,再用 del dict4["涨跌幅"] 删除键后输出。 请按平台原始题面原样输入(注释除外),判定以平台为准。
# 注:平台题面为填空形式,下方展示的是填空完成后的参考形态;请按平台原始题面原样输入,以平台判定为准
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#任务一
dict1 = {"汇率变量":"美元兑人民币","日期":"2024-08-30","中间价":"7.1124","涨跌幅":"-0.0025"}
dict2 = {"汇率变量":"欧元兑人民币","日期":"2024-08-21","中间价":"7.9325","涨跌幅":"0.0038"} # 定义字典dict2
dict3 = {"汇率变量":"港元兑人民币","日期":"2024-08-19","中间价":"0.9162","涨跌幅":"-0.0003"} # 定义字典dict3
dict4 = {"汇率变量":"英镑兑人民币","日期":"2024-08-08","中间价":"9.0701","涨跌幅":"0.0011"} # 定义字典dict4
print(dict1.keys()) #输出字典dict1的全部键码
print(dict2.values()) #输出字典dict2的全部数值
print(dict3.items()) #输出字典dict3的全部元素
#任务二
dict1 = {"汇率变量":"美元兑人民币","日期":"2024-08-30","中间价":"7.1124","涨跌幅":"-0.0025"}
dict2 = {"汇率变量":"欧元兑人民币","日期":"2024-08-21","中间价":"7.9325","涨跌幅":"0.0038"} # 定义字典dict2
dict4 = {"汇率变量":"英镑兑人民币","日期":"2024-08-08","中间价":"9.0701","涨跌幅":"0.0011"} # 定义字典dict4
print(dict1["日期"]) #查询美元兑人民币汇率的具体日期
print(dict2["中间价"]) #查询欧元兑人民币汇率的中间价
print(dict4["涨跌幅"]) #查询英镑兑人民币的涨跌幅
#任务三
dict2 = {"汇率变量":"欧元兑人民币","日期":"2024-08-21","中间价":"7.9325","涨跌幅":"0.0038"}
dict2["日期"] = "2024-08-29" #修改字典2新的日期
dict2["中间价"] = 7.9318 #修改字典2新的中间价
dict2["涨跌幅"] = -0.0037 #修改字典2新的涨跌幅
print(dict2) # 输出变量dict2的值
#任务四
dict3 = {"汇率变量":"港元兑人民币","日期":"2024-08-19","中间价":"0.9162","涨跌幅":"-0.0003"}
#使用update函数在dict3中添加"前一日中间价":"0.9165","前一日涨跌幅":"0.0002"
dict3.update({"前一日中间价":"0.9165","前一日涨跌幅":"0.0002"})
print(dict3) # 输出任务四
dict4 = {"汇率变量":"英镑兑人民币","日期":"2024-08-08","中间价":"9.0701","涨跌幅":"0.0011"} # 定义字典dict4
del dict4["涨跌幅"] #删除dict4的涨跌幅
print(dict4) # 输出变量dict4的值预期输出(本机实际运行结果,具体以平台运行结果为准):
dict_keys(['汇率变量', '日期', '中间价', '涨跌幅'])
dict_values(['欧元兑人民币', '2024-08-21', '7.9325', '0.0038'])
dict_items([('汇率变量', '港元兑人民币'), ('日期', '2024-08-19'), ('中间价', '0.9162'), ('涨跌幅', '-0.0003')])
2024-08-30
7.9325
0.0011
{'汇率变量': '欧元兑人民币', '日期': '2024-08-29', '中间价': 7.9318, '涨跌幅': -0.0037}
{'汇率变量': '港元兑人民币', '日期': '2024-08-19', '中间价': '0.9162', '涨跌幅': '-0.0003', '前一日中间价': '0.9165', '前一日涨跌幅': '0.0002'}
{'汇率变量': '英镑兑人民币', '日期': '2024-08-08', '中间价': '9.0701'}
# 方式1:字面量语法(推荐)
# 花括号{}是字典的字面量语法
# 键值对格式: 键:值,使用冒号分隔
stock_codes_a = {
'600': '上证A股',
'900': '上证B股',
'000': '深证A股',
'200': '深证B股',
'400': '三板市场股票'
}
# 方式2:dict()构造函数
# 先创建空字典,然后逐个添加键值对
stock_codes_b = dict() # 创建空字典
stock_codes_b['600'] = '上证A股' # 添加键值对
stock_codes_b['900'] = '上证B股'
stock_codes_b['000'] = '深证A股'
stock_codes_b['200'] = '深证B股'
stock_codes_b['400'] = '三板市场股票'
# 方式3:dict.fromkeys()批量创建
# 适用于创建所有值相同的字典
codes = ['600', '900', '000'] # 键列表
default_value = '其他' # 默认值
stock_codes_c = dict.fromkeys(codes, default_value)
# 打印字典内容
# 字典的字符串表示格式为 {键: 值, ...}
print('字典A:', stock_codes_a)
# 通过键访问值
# stock_codes_a['000']获取键'000'对应的值
print(f"\n'000'对应: {stock_codes_a['000']}") # 输出: 深证A股代码深度解析:
字典的内存结构:
# CPython 3.8+的字典使用紧凑表(Compact Table) # 每个条目占用24字节: # - 哈希值: 8字节 # - 键指针: 8字节 # - 值指针: 8字节 # 对于5个键值对的字典: # 内存占用 ≈ 5 × 24 = 120字节 + 开销哈希冲突的实际影响:
# 演示哈希冲突 # 假设两个不同的键产生相同的哈希值(简化示例) dict1 = {} dict1['apple'] = 1 # 假设'banana'的哈希值与'apple'冲突 dict1['banana'] = 2 # Python会自动处理冲突 # 对用户透明,无需关心内部实现 print(dict1) # {'apple': 1, 'banana': 2}创建方式的性能对比:
import time # 方式1:字面量(最快) start = time.time() for _ in range(100000): d = {'a': 1, 'b': 2, 'c': 3} print(f'字面量: {time.time() - start:.4f}秒') # 方式2:dict()构造函数 start = time.time() for _ in range(100000): d = dict(a=1, b=2, c=3) print(f'dict(): {time.time() - start:.4f}秒')金融应用:股票代码分类:
# 中国股票代码规则: # - 600xxx, 601xxx, 603xxx: 上交所主板 # - 300xxx: 深交所创业板 # - 688xxx: 上交所科创板 code_classification = { '600': '上交所主板', '601': '上交所主板', '603': '上交所主板', '300': '创业板', '688': '科创板' } # 查询股票类别 def classify_stock(code): prefix = code[:3] # 获取前3位 return code_classification.get(prefix, '未知类别') print(classify_stock('600519')) # 上交所主板 print(classify_stock('300750')) # 创业板
44.4 字典的操作
字典的增删查改为何能保持平均O(1)?答案在它底层的哈希表实现:
理论背景:哈希表的实现原理
Python字典(Dict)是基于哈希表(Hash Table)实现的关联数据结构。从计算机科学的角度来看,字典是抽象数据类型(Abstract Data Type)Map的一种高效实现:
- 键值对映射(Key-Value Mapping): 每个键(Key)唯一对应一个值(Value)
- 哈希函数(Hash Function):
hash(key) → 整数索引,将键转换为数组索引 - 冲突解决(Collision Resolution): 处理多个键映射到同一索引的情况
哈希函数本身的性质决定了冲突处理的代价:
数学分析:哈希函数的设计
理想哈希函数应该满足:
\[ \forall key_1 \neq key_2: hash(key_1) \neq hash(key_2) \]
但实际上,由于键空间远大于数组大小,冲突不可避免。Python使用以下策略:
- 开放寻址法(Open Addressing): 当发生冲突时,寻找下一个空闲槽位
- 探测序列(Probe Sequence): \(h(k, i) = (h_1(k) + i \cdot h_2(k)) \mod m\) 其中\(i\)是探测次数,\(h_1\)和\(h_2\)是两个哈希函数
时间复杂度分析:
| 操作 | 平均情况 | 最坏情况 | 说明 |
|---|---|---|---|
| 插入 | O(1) | O(n) | 负载因子< 0.66时 |
| 查找 | O(1) | O(n) | 同上 |
| 删除 | O(1) | O(n) | 同上 |
Python字典保持负载因子(Load Factor)低于2/3,确保平均性能为O(1)。
补充说明:为什么字典查找比列表快数百倍?
假设有1000只股票:
- 列表查找: 平均需要500次比较(O(n))
- 字典查找: 只需1次哈希计算(O(1))
性能差异: 500倍!这正是高频交易系统使用字典存储订单簿的原因。
# 创建股票代码到名称的映射
# 键是股票代码(字符串),值是股票名称(字符串)
stock_dict = {
'600519.SH': '贵州茅台',
'000858.SZ': '五粮液',
'600036.SH': '招商银行'
}
# 访问元素:使用get()方法(推荐)
# get()方法在键不存在时返回默认值,不会报错
# 语法: dict.get(key, default_value)
print('查询600519.SH:', stock_dict.get('600519.SH', '未知'))
# 输出: 贵州茅台
# 查询不存在的键
print('查询999999.XX:', stock_dict.get('999999.XX', '未知'))
# 输出: 未知 (如果用stock_dict['999999.XX']会报KeyError)
# 添加新键值对
# 如果键已存在,会覆盖原值
stock_dict['601318.SH'] = '中国平安'
# 删除键值对
# del语句会从字典中移除键,如果键不存在会报KeyError
del stock_dict['600036.SH'] # 删除'招商银行'
# 获取所有键
# keys()返回dict_keys对象,需要转换为列表查看
print(f'\n键: {list(stock_dict.keys())}')
# 输出: ['600519.SH', '000858.SZ', '601318.SH']
# 获取所有值
# values()返回dict_values对象
print(f'值: {list(stock_dict.values())}')
# 输出: ['贵州茅台', '五粮液', '中国平安']
# 获取字典大小
# len()函数返回键值对的数量
print(f'项数: {len(stock_dict)}') # 输出: 3代码深度解析:
访问方式的对比:
# 方式1:直接访问(键不存在时报错) try: name = stock_dict['999999.XX'] except KeyError: print('键不存在!') name = None # 方式2:get()方法(键不存在时返回默认值) name = stock_dict.get('999999.XX', None) # 方式2更安全,推荐使用删除操作的安全性:
# 方法1:del语句(键不存在时报错) # del stock_dict['999999.XX'] # KeyError! # 方法2:pop()方法(键不存在时返回默认值) removed = stock_dict.pop('999999.XX', None) print(removed) # None (不会报错) # 方法3:popitem()删除并返回最后一个键值对 # Python 3.7+中,字典保持插入顺序 key, value = stock_dict.popitem() print(f'删除了: {key} -> {value}')字典更新操作:
# update()方法:批量更新字典 new_stocks = { '000001.SZ': '平安银行', '601318.SH': '中国平安(更新)' } stock_dict.update(new_stocks) # 如果键已存在,会更新值 # 如果键不存在,会添加新键值对金融应用:实时行情更新:
# 模拟实时行情更新 quotes = { '600519.SH': 1850.00, '000858.SZ': 220.50 } # 更新价格 def update_price(code, new_price): if code in quotes: # 检查键是否存在 old_price = quotes[code] quotes[code] = new_price change = (new_price - old_price) / old_price print(f'{code} 更新: {old_price:.2f} -> {new_price:.2f} ({change:+.2%})') else: quotes[code] = new_price print(f'{code} 新增: {new_price:.2f}') update_price('600519.SH', 1860.00) # 更新 update_price('000001.SZ', 18.50) # 新增
44.5 字典的遍历
遍历顺序与字典”是否有序”直接相关,先辨析一个常见的版本疑问:
易混淆概念辨析:Python 3.6 vs 3.7的字典有序性
- Python 3.6: 字典有序是实现细节(CPython的副作用)
- Python 3.7+: 字典有序成为语言规范(官方保证)
因此,在Python 3.7+中,可以放心依赖字典的插入顺序。
# 创建股票价格字典
# 键是股票名称,值是股票价格
prices = {'贵州茅台': 1850, '五粮液': 220, '招商银行': 45}
# 方式1:遍历键
# for key in dict: 等价于 for key in dict.keys():
print('遍历键:')
for key in prices:
print(f' {key}')
# 输出:
# 贵州茅台
# 五粮液
# 招商银行
# 方式2:遍历键值对
# items()方法返回(键, 值)元组的迭代器
print('\n遍历键值对:')
for key, value in prices.items():
# 同时解包键和值
print(f' {key}: {value}元')
# 输出:
# 贵州茅台: 1850元
# 五粮液: 220元
# 招商银行: 45元
# 方式3:遍历值
# values()方法返回值的迭代器
print('\n遍历值:')
for value in prices.values():
print(f' {value}元')
# 字典推导式:创建新字典的优雅方式
# 语法: {键表达式: 值表达式 for item in iterable}
# 下面的代码将字典的键值对反转
inverted = {v: k for k, v in prices.items()}
print(f'\n反转字典: {inverted}')
# 输出: {1850: '贵州茅台', 220: '五粮液', 45: '招商银行'}
# 注意:如果原字典的值不唯一,反转会丢失数据!
# 因为字典的键必须唯一代码深度解析:
遍历方式的性能对比:
import time large_dict = {i: i**2 for i in range(1000000)} # 方式1:遍历键 start = time.time() for key in large_dict: _ = large_dict[key] print(f'遍历键: {time.time() - start:.4f}秒') # 方式2:遍历键值对 start = time.time() for key, value in large_dict.items(): _ print(f'遍历键值对: {time.time() - start:.4f}秒') # 方式2稍快,因为避免了额外的哈希查找字典推导式的应用:
# 应用1:过滤字典 # 找出价格大于100的股票 expensive = {k: v for k, v in prices.items() if v > 100} print(expensive) # {'贵州茅台': 1850, '五粮液': 220} # 应用2:转换字典值 # 将价格转换为万元 prices_wan = {k: v/10000 for k, v in prices.items()} print(prices_wan) # {'贵州茅台': 0.185, '五粮液': 0.022, '招商银行': 0.0045} # 应用3:合并两个字典 dict1 = {'a': 1, 'b': 2} dict2 = {'c': 3, 'd': 4} merged = {**dict1, **dict2} # Python 3.5+的解包语法 print(merged) # {'a': 1, 'b': 2, 'c': 3, 'd': 4}金融应用:计算投资组合权重:
# 持仓价值 holdings = { '贵州茅台': 185000, '五粮液': 44000, '招商银行': 22500 } total = sum(holdings.values()) # 计算权重 weights = {stock: value/total for stock, value in holdings.items()} print('持仓权重:') for stock, weight in sorted(weights.items(), key=lambda x: -x[1]): print(f' {stock}: {weight:.2%}')内存视图:字典的内部结构:
# 查看字典的内存占用 import sys small_dict = {'a': 1, 'b': 2} print(f'字典大小: {sys.getsizeof(small_dict)}字节') # 字典包含多个部分: # - 哈希表(主要部分) # - 条目数组(存储键值对) # - 元数据(大小、版本等)
44.6 金融应用股票代码映射
# 股票代码到名称的映射
# 这是一个典型的"查找表"(Lookup Table)应用场景
# 字典的O(1)查找性能使得它非常适合此类应用
code_to_name = {
'600519.SH': '贵州茅台',
'000858.SZ': '五粮液',
'600036.SH': '招商银行',
'601318.SH': '中国平安',
'000001.SZ': '平安银行'
}
# 批量查询的股票代码列表
codes_to_query = ['600519.SH', '000858.SZ', '000001.SZ']
# 遍历并查询
print('股票查询结果:')
for code in codes_to_query:
# 使用get()方法,如果代码不存在返回'未知股票'
# 这避免了KeyError异常
name = code_to_name.get(code, '未知股票')
print(f'{code}: {name}')
# 反向映射:从名称到代码
# 使用字典推导式交换键和值
# 注意:如果名称不唯一,会丢失数据!
name_to_code = {v: k for k, v in code_to_name.items()}
# 查询平安银行的代码
# 使用get()方法,如果名称不存在返回None
print(f'\n平安银行代码: {name_to_code.get("平安银行")}')
# 输出: 000001.SZ
# 查询不存在的名称
print(f'腾讯代码: {name_to_code.get("腾讯")}')
# 输出: None (不会报错)代码深度解析:
双向映射的设计模式:
# 更健壮的双向映射实现 class BidirectionalMap: def __init__(self): self.key_to_value = {} self.value_to_key = {} def add(self, key, value): # 检查值是否已存在 if value in self.value_to_key: raise ValueError(f'值{value}已存在!') self.key_to_value[key] = value self.value_to_key[value] = key def get_key(self, value): return self.value_to_key.get(value) def get_value(self, key): return self.key_to_value.get(key) # 使用示例 bm = BidirectionalMap() bm.add('600519.SH', '贵州茅台') print(bm.get_key('贵州茅台')) # 600519.SH print(bm.get_value('600519.SH')) # 贵州茅台默认字典的应用:
from collections import defaultdict # 使用defaultdict避免手动检查键是否存在 # 当访问不存在的键时,自动创建默认值 counter = defaultdict(int) # 默认值为0 # 统计股票出现次数 codes = ['600519.SH', '000858.SZ', '600519.SH', '600519.SH'] for code in codes: counter[code] += 1 # 即使code不存在,也不会报错 print(counter) # defaultdict(<class 'int'>, {'600519.SH': 3, '000858.SZ': 1})嵌套字典的应用:
# 存储股票的多维度信息 stock_info = { '600519.SH': { 'name': '贵州茅台', 'price': 1850.00, 'pe': 45.2, 'market_cap': 2325000000000 # 市值(元) }, '000858.SZ': { 'name': '五粮液', 'price': 220.50, 'pe': 32.8, 'market_cap': 856000000000 } } # 访问嵌套信息 maotai = stock_info['600519.SH'] print(f'{maotai["name"]}: PE={maotai["pe"]}, 市值={maotai["market_cap"]/1e8:.0f}亿元')OrderedDict的应用:
from collections import OrderedDict # OrderedDict在Python 3.7+之前很有用 # 在Python 3.7+中,普通dict已经有序 # 维护时间序列数据 time_series = OrderedDict() time_series['2024-01-01'] = 1850.0 time_series['2024-01-02'] = 1860.5 time_series['2024-01-03'] = 1855.0 # 获取最近的价格 latest_date = next(reversed(time_series)) latest_price = time_series[latest_date] print(f'最新价格({latest_date}): {latest_price}')
性能优化技巧:
预分配字典大小(如果可能):
# 对于已知大小的字典,预分配可以提高性能 d = {} d.update({i: i**2 for i in range(1000)}) # 比逐个插入更快使用
__slots__减少内存:class Stock: __slots__ = ['code', 'name', 'price'] def __init__(self, code, name, price): self.code = code self.name = name self.price = price # 使用对象而非字典可以减少内存占用避免频繁的字典操作:
# 不推荐 for stock in stocks: if stock['code'] not in cache: cache[stock['code']] = {} cache[stock['code']]['price'] = stock['price'] # 推荐 for stock in stocks: if stock['code'] in cache: cache[stock['code']]['price'] = stock['price'] else: cache[stock['code']] = {'price': stock['price']}
最佳实践总结:
使用字典的场景:
- 需要通过键快速查找值
- 键是字符串或数字等不可变类型
- 需要维护键值对关系
- 数据需要频繁查询
避免字典的场景:
- 需要保持顺序(Python 3.6-)
- 需要序列化(考虑使用OrderedDict)
- 键是可变类型(如列表)
字典vs列表的选择决策树:
需要通过特定标识符查找数据? ├─ 是 → 使用字典 └─ 否 → 需要按顺序访问? ├─ 是 → 使用列表 └─ 否 → 使用集合(去重)
44.7 本章小结
要点:
- 字典按键存取,键唯一且必须是不可变类型;Python 3.7+ 的字典保持插入顺序
- 创建方式:字面量
{}一次成型、dict()加逐个赋值动态构建、dict.fromkeys()批量建同值字典 - 增改:
d[k] = v(键存在则覆盖)、update()批量增改;删除:del d[k]、pop()、popitem() keys()、values()、items()返回视图对象,可直接迭代与做成员判断,查看完整内容需list()- 三种遍历方式(键、键值对、值);字典推导式
{v: k for k, v in d.items()}可反转字典,但值不唯一时会丢数据
易错点:
- 用
d[key]访问不存在的键会抛KeyError,稳妥写法是d.get(key, 默认值) update()对已存在的键执行的是覆盖,不是追加- 平台任务三把”中间价”从字符串
'7.9325'改成了数值7.9318,值的类型随之改变;后续做数值运算前要先统一类型 - 用列表等可变对象作键会抛
TypeError
44.8 动手与思考
以下练习每题附参考答案(默认折叠)。请先独立完成并写下你的判断,再点开对照,最后上机验证。
概念自测(不看正课):
keys()、values()、items()各返回什么?为什么字典查找平均是 O(1)?字典的值不唯一时用推导式反转会发生什么?参考答案(点开前请先独立完成)
解题思路:
keys()、values()、items()分别返回字典的键视图、值视图、键值对视图(items()的元素是(键, 值)元组);视图是动态的,随字典增删自动更新,常配list()或 for 循环使用。平均 O(1) 的原因:字典底层是哈希表,对键计算哈希值即可直接定位存储位置,查找代价与字典大小无关(不理想时退化为 O(n),但平均是常数级)。值不唯一时用{v: k for k, v in d.items()}反转,重复的值作为新键会相互覆盖,最终只保留遍历中最后出现的那个键值对——反转前应先确认值唯一。回扣主线章:字典的创建、访问与视图的讲解见第 章节 2 章。
输出预测:不运行代码,先写出下面代码的输出结果,再上机检验你的判断。
d = {'汇率变量': '美元兑人民币', '日期': '2024-08-30', '中间价': '7.1124'} print(list(d.keys())) print(d['中间价']) d['涨跌幅'] = '-0.0025' d.update({'前一日中间价': '7.1131'}) print(len(d)) print(d.get('前一日涨跌幅', '无数据'))参考答案(先写下你的预测再点开)
解题思路:初始
d有 3 个键,list(d.keys())输出['汇率变量', '日期', '中间价'];d['中间价']按键取值输出7.1124(值本身是字符串,打印不带引号);d['涨跌幅'] = '-0.0025'新增一个键、d.update(...)再新增“前一日中间价”一个键,此时共 5 个键,len(d)输出5;d.get('前一日涨跌幅', '无数据')查询的键不存在,返回默认值无数据(用d[键]则会抛KeyError,这正是get的稳妥之处)。# 验证脚本:原样运行题面代码 d = {'汇率变量': '美元兑人民币', '日期': '2024-08-30', '中间价': '7.1124'} # 汇率信息字典 print(list(d.keys())) # 输出全部键组成的列表 print(d['中间价']) # 按键查询中间价 d['涨跌幅'] = '-0.0025' # 新增键值对 d.update({'前一日中间价': '7.1131'}) # 批量更新(此处为新增) print(len(d)) # 输出键值对个数 print(d.get('前一日涨跌幅', '无数据')) # 键不存在时返回默认值预期输出(本机 peter 环境实际运行结果,具体以平台运行结果为准):
['汇率变量', '日期', '中间价'] 7.1124 5 无数据回扣主线章:键查询与
get()的稳妥写法见第 章节 2 章。动手验证:先执行
del d['日期']并输出字典,确认键值对已被删除;再尝试d[['a', 'b']] = 1,捕获错误并说出字典键必须满足什么要求。参考答案(点开前请先独立完成)
解题思路:
del d['日期']把“日期”键及其值一起删除(不是置空,是键值对整体消失),输出可见该键已不在。d[['a', 'b']] = 1抛TypeError: unhashable type: 'list'——字典的键必须是可哈希的不可变类型(字符串、数值、元组等);列表可变、不可哈希,无法作为键。若确实要用多个字段作键,应改用元组d[('a', 'b')] = 1。# 验证脚本:删除键值对,以及不可哈希类型作键的报错 d = {'汇率变量': '美元兑人民币', '日期': '2024-08-30', '中间价': '7.1124', '涨跌幅': '-0.0025'} # 含日期键的汇率字典 del d['日期'] # 删除日期键及其值 print(d) # 输出删除后的字典,日期键已消失 try: d[['a', 'b']] = 1 # 尝试用列表作键(预期报错) except TypeError as error_msg: print('错误类型:', type(error_msg).__name__, '|', error_msg) # 捕获并输出错误预期输出(本机 peter 环境实际运行结果,具体以平台运行结果为准):
{'汇率变量': '美元兑人民币', '中间价': '7.1124', '涨跌幅': '-0.0025'} 错误类型: TypeError | unhashable type: 'list'回扣主线章:
del删除键值对与键的可哈希要求见第 章节 2 章。变式任务(平台任务三、四同型改造):仿照任务三把”日期”改为下一个交易日,仿照任务四用一次
update()同时新增”开盘价”与”最高价”两个键,最后del掉”涨跌幅”并输出最终字典。参考答案(点开前请先独立完成)
解题思路:改值用
d[已有键] = 新值,一次只改一个键;批量新增用一次update()传入含两个键值对的字典;删除用del d[键]。三步之后字典剩“汇率变量、日期、中间价、开盘价、最高价”五个键。# 变式程序:改值、批量新增、删除三步维护汇率字典 rate_dict = {'汇率变量': '美元兑人民币', '日期': '2024-08-30', '中间价': '7.1124', '涨跌幅': '-0.0025'} # 初始字典 rate_dict['日期'] = '2024-09-02' # 仿照任务三:把日期改为下一个交易日 rate_dict.update({'开盘价': '7.1100', '最高价': '7.1188'}) # 仿照任务四:一次update新增两个键 del rate_dict['涨跌幅'] # 删除涨跌幅键值对 print(rate_dict) # 输出最终字典预期输出(本机 peter 环境实际运行结果,具体以平台运行结果为准):
{'汇率变量': '美元兑人民币', '日期': '2024-09-02', '中间价': '7.1124', '开盘价': '7.1100', '最高价': '7.1188'}注意:以上为本题变式的独立代码;列表 44.1 对应平台任务的原始代码块仍须原样输入教学平台,不要用本变式替换。
回扣主线章:字典改值、
update()与del的同型操作见第 章节 2 章。